package com.growthgate.bootcommon.handler;

import com.fasterxml.classmate.ResolvedType;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import io.swagger.annotations.ApiModelProperty;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import springfox.documentation.schema.Annotations;
import springfox.documentation.service.AllowableListValues;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;
import springfox.documentation.swagger.schema.ApiModelProperties;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * API模型属性处理器
 *
 * @author GrowthGate
 * @date 2020/2/20
 */
@Component
public class ApiModelPropertyHandler implements ModelPropertyBuilderPlugin {

    @Override
    public void apply(@NotNull ModelPropertyContext context) {
        Optional<ApiModelProperty> annotation = Optional.empty();
        Class<?> rawPrimaryType = null;
        if (context.getAnnotatedElement().isPresent()) {
            // 使用 ApiParameterHandler 生成的类
            Field field = (Field) context.getAnnotatedElement().get();
            annotation = ApiModelProperties.findApiModePropertyAnnotation(field).toJavaUtil();
            rawPrimaryType = field.getType();
        } else if (context.getBeanPropertyDefinition().isPresent()) {
            // 普通实体类
            BeanPropertyDefinition beanPropertyDefinition = context.getBeanPropertyDefinition().get();
            annotation = Annotations.findPropertyAnnotation(beanPropertyDefinition, ApiModelProperty.class).toJavaUtil();
            rawPrimaryType = beanPropertyDefinition.getRawPrimaryType();
        }
        // 过滤得到目标类型
        if (annotation.isPresent() && rawPrimaryType.isEnum()) {
            // 生成枚举描述
            StringBuilder description = new StringBuilder(annotation.get().value());
            if (description.length() > 0) {
                description.append('\n');
            }
            // 获取枚举值
            Enum<?>[] enums = (Enum<?>[]) rawPrimaryType.getEnumConstants();
            List<String> ordinals = Arrays.stream(enums).map(e -> {
                description.append(e.ordinal()).append(": ").append(e.toString()).append('\n');
                return Integer.toString(e.ordinal());
            }).collect(Collectors.toList());
            AllowableListValues allowableListValues = new AllowableListValues(ordinals, rawPrimaryType.getTypeName());
            // 固定设置为int类型
            ResolvedType resolvedType = context.getResolver().resolve(int.class);
            context.getBuilder().description(description.toString()).allowableValues(allowableListValues).type(resolvedType);
        }
    }

    @Override
    public boolean supports(DocumentationType documentationType) {
        return true;
    }

}